Java Programming Language

It is expected that the reader will gain knowledge and comprehension of the Java language such that application of the learning can be demonstrated by writing progressively more complex programs. The approach to the Java syntax is to build from the lowest level to the higher orders of program structure. The main division of the syntax will be made between logic statement syntax and program structure statement syntax. Logic statement syntax encompasses data types, expressions, variable declarations, if/else and switch conditional statements, while, do and for looping statements, and simple method calling and I/O calls. Program structure statement syntax encompasses arrays, class and object definition, complex method calling, exception handling, and packaging. How the Object-Oriented paradigm is incorporated into the Java syntax will also be explored.

Java Structure Statement Syntax

The structural statements in Java are used to construct classes from which objects are created and to facilitate object interaction from which programs can be written. The syntax of these sets of statements is the way in which Java uses to express the concepts of Object-Oriented programming. The Java language provides syntax to define classes, instantiate objects, implement abstraction, encapsulation, inheritance and polymorphic behavior. Other structural statements are provided to handle runtime exceptions and to package collections of objects into a complete system.

Java Objects, Arrays and Strings

The heart of the Java language is an object. An object is a self-contained entity that implements a set of behaviors related to the purpose of the object. In Java arrays and strings are actually objects but have some special characteristics apart from objects in general. These special characteristics are provided so that the array and string objects can be easily integrated into the syntax of Java statements because arrays and string are so common to programming tasks. In this section we will explore the details of how arrays, string and object in general are expressed in Java.

Arrays

An array is an ordered collection, or numbered list, of values. The values can be any of the primitive types, objects or even other arrays, but all the values in an array must be of the same type. In other words, if an array is declared to be of type int then all the values in the array must be of type int. If an array is declared to be of a certain object type the all the values in the array must be of that object type. In this section we will learn about the Java syntax of arrays to declare, create, use and assign literal values for both single and multidimensional arrays.

Declaring

The syntax to declare an array in Java is similar to declaring other variables. First the type (the single type of values the array will contain) is declared, followed by the characters []. Then the name of the array is specified as a Java identifier.

Examples:

byte[] arrayOfBytes; //array of type byte

byte[][] arrayOfArrayOfBytes; //multidimensional array of bytes

Point[] points; //an array of the object Point

int[] arrayOfInt; //array of int values, it is of type int

This syntax simply declares the type, number of dimensions and name of an array. It does not actually create the array; no memory is yet allocated to contain the array and all its values.

Creating

Once an array has been declared it can then be created. Since an array in Java is a composite or reference type variable and is similar to an object it must created with the new operator. The new operator signifies that an object, or in this case a special type of object, an array, is to be created. Memory is allocated and reserved for the array when it is created. The syntax of creating an array is to assign an array name to an expression of the new operator. This means that an identifier (the array name) is assigned (using the = symbol) to an expression using the new operator (new arraytype[# of array slots];). Once an array is created its size cannot be changed without creating another array and copying the values from the old array to the new array. The number of array slots must be a non-negative integer value of size int or smaller. Interestingly, the char type can be used as integer value because it is a 16-bite value that is the Unicode number of a character.

Examples:

buffer = new byte[1024];

lines = new String[50];

points = new Point[2000];

products = new int[10][10]; //multidimensional (2) creation of an array of ints

When arrays are created each element value in the array is initialized to a default value according to the type of the array. Boolean arrays are initialized to false, '\u0000' for char, 0 for integers, 0.0 for float-point and null for objects or other array values.

It is common to combine the syntax of the array declaration with the array creation. This is shown in the following examples.

Examples:

byte[] buffer = new byte[1024];

String[] lines = new String[50];

Point[] points = new Point[2000];

int[][] products = new int[10][10];

Common errors when declaring and creating arrays is to forget the = sign and the new operator and/or to put the [# of slots] specification in the wrong place. Because arrays are a type of object in Java, their syntax is different than other older languages.

Using

Once an array is declared and created it can be used. Elements within an array are accessed by an index number that starts at zero (0) and increases sequentially by whole numbers to the index value that is one less than the number of slots created for the array. For example, if an array is created with 1024 slots then the index is 0, 1, 2, … 1023. In using an array you can get the value at a certain index or set a value at a certain index. As stated earlier the index value must be an integer of size int or smaller. It is preferrable to use type int for all array indexing.

To get a value you assign a variable to the arrayname[index#].

Examples:

int a = arrayOfInt[5];

int product = products[3][7];

String s = lines[49+a];

int i = 0;

byte b = buffer[i];

To set a value you assign an arrayname[index#] to a value or expression.

Examples:

lines[i+3] = "Hello There";

product[3][7] = 3*(5+8);

arrayOfInt[4] = 123;

Java checks that the index value you use to access an array element is in bounds, that it is a positive number from zero (0) to the size of the array less one. If the index is out of bounds then a runtime exception occurs. Dealing with exceptions is covered in a latter section.

One further useful piece of information that can be obtained from an array at runtime is how many elements it has. Because arrays are created at runtime with the new operator and the length is specified, the length can be obtained at a later point in the program's execution. Each array has an intrinsic property called length. The property contains the number of elements in the array. It is the same value as what was used to create that particular array. For example, if the array was declared and created as int[] arrayOfInt[10]; then the length of the array is 10. To obtain this length value simply specify the arrayname followed by a period (.) and the property name length.

Examples:

int a = arrayOfInt.length;

Notice this is the same as the object.member expression syntax, in this case the object is the arrayname without the []. You can get the length, but you cannot set the length; this is only done when an array is created with the new operator.

Literals

Arrays can be initialized to contain values with special declaration syntax. One form is to declare that the array contains nothing. Declaring the array to be assigned to null does this. For example, char[] password = null; Another, more common form is to list a series of values for the array elements to contain. This syntax is combined with the declaration syntax and implicitly creates an array. Because of the special syntax, Java knows the size of the array and that it should automatically create the array at runtime. For this reason, the new operator and the [# of elements] syntax is absent. This syntax is as follows.

Example:

int[] powersOfTwo = {1, 2, 4, 8, 16, 32, 64, 128};

Notice that the initial values are in curly braces {}, there is no new operator, there is no type[# of elements] syntax and that the trailing } is followed by a ;. The size is determined by the number of values with curly braces {} and the trailing semicolon (;) signifies that the declaration is complete. Normally, a semicolon (;) is not placed behind a closing curly brace } in statement blocks. The values are assigned from left to right to the array slots from zero to the length minus one.

Another feature of the Java array syntax is that an array can be declared and initialized with values without giving the array a name. These are known as anonymous arrays and are used as parameter in a method call.

Examples:

String response = askQuestion("Do you want to quit?", new String[] {"Yes", "No"});

The second parameter in this example is an array containing the possible responses. A reference to the array is passed to the method which will access the array with the parameter name that the method declares to hold the array variable. The syntax in the method call creates the array and the literal values in the curly braces supply the array size and the values of the elements. Once the method returns the reference to the array is de-allocated. Since we didn't need to access the array outside of the askQuestion method it was created as an anonymous array. This second form of array initialization can be used with array names also. This form allows the array to be initialized after it has been declared. The differences from the declaration and initialization together form are that in the separate initialization the new operator is used.

Example:

int[] powersOfTwo;

powersOfTwo = new int[] { 1, 2, 4, 8, 16, 32, 64, 128 };

Array literal initialization does have the drawback that the memory allocation and value initialization is done at runtime and not compile time. Large arrays with literal initialization will cause a Java program to be larger and have some execution time dedicated to initializing an array. Therefore, avoid large literal array initializations, it is better to read the values in from a file to initialize a large array because control is given to your program sooner. In that way you could give the user some visual clue that they need to wait a moment.

Multidimensional

In Java multidimensional arrays are the same as arrays of arrays. This means that, for example, a two dimensional array, each of 10 elements (int[][] arrayOfInt = new int[10][10];) is ten arrays each containing ten elements of type int. Conceptually this is 100 elements of int in a ten by ten table but in implementation it is ten arrays of ten int elements each. In other words, the declaration:

int[][] products = new [10][10];

is equivalent to:

int[][] products = new [10][];

for (int i=0; i<10; i++)

{

product[i] = new int[10];

}

Notice in the declaration of the second code fragment that the right-most [] has no size value in it. This is done within the for loop. This help to illustrate that this is an array of ten arrays each with ten int elements in them. This can give you some more expressive power in using arrays in Java because you have more runtime control over the creation and sizing of arrays.

Copying, Cloning and Comparing

Arrays are composite data types, meaning that they contain a composition of values. The array variable contains a reference to the beginning of the entire array data. Individual values in the array are accessed by the index of a particular element. Thus, copying and comparing arrays is not as simple as copying and comparing primitive (single value) data types. With primitive data types (boolean, char, byte, short, int, long, float, double) you only have the single value accessible by the variable name, you do not have the reference (memory location) of the variable. So, with primitive data types you can make copies of variables by simply assigning a variable to another variable, each of the same type. Similarly you can compare primitive data type variables with the comparative operators (==, !=, <, <). However, with arrays there is an added difficulty of distinguishing between copying and comparing the array reference and the array values.

Examples:

int x = 3;
int y = x;
//at this point both x & y contain the value 3
//but they are separate variables.

char[] greet = { ‘h’,’e’,’l’,’l’,’o’ }; //greet holds ref to char array
char[] cuss = greet; //cuss hold the same reference
cuss[4] = ‘!’; //use 2nd reference to change the single char array
System.out.println(greet); //prints "hell!"

These examples show the difference between the copying of primitive data types and copying references to arrays (a composite type). To copy the value in one array to another, two different techniques can be used. The first is to construct a loop that will copy the values in a source array into a destination array.

Example:

int[] a = { 1, 2, 3, 4 };
int[] b = { 0, 0, 0, 0 };
for (int i = 0; i < a.length; i++)
{
	b[i] = a[i];
}

The second techniques is to use the clone method that is inherited by all objects (an array is an object) from the root parent of all objects java.lang.Object).

Example:

int[] a = { 1, 2, 3, 4 };
int[] b = (int[]) a.clone();

A cast is necessary because the clone method returns a type of Object. This "generic" Object must be cast into the actual data type needed. The clone method only copies the values (which may be references to other composite types) at the first level of the array. This is known as "shallow" copying. To make a copy that resolves references within an array to it final value, the default clone method must be overridden by your own clone method in your object. This is exemplified in the copying of a multidimensional array this is a "deep" copy.

Example:

int[][] a = { {1,2,3}, {4,5}}; //create 2 dim. array, init. with values
int[][] b = new int[a.length][]; //create 2 dim. array
for (int i = 0; i < a.length; i++)
{
	b[i] = (int[]) a[i].clone();
}

This uses the for loop copy technique to deal with the first dimension array references and the clone method technique to copy the value in the second dimension.

Similarly, comparing primitive data type with the == operator compares the value, but comparing composite type with the == operator compares the reference, not the set of values. If you want to compare two separate arrays (each referring to different locations) to test if all the values in the arrays are equivalent then use the java.util.Arrays.equals() method.

Example:

byte[] a = {1, 2, 3};
byte[] b = (byte[]) a.clone();
if (a==b) System.out.println("equal"); //they are NOT equal
if (java.util.Arrays.equals(a,b)) System.out.println("a,b equivalent");
//they ARE equivalent

Syntax Summary

int[] regions = new int[10]; //declare & create an array

regions[0] = 100; //set an array element value

regions[1] = 200;

regions[9] = 1000;

int a;

a = regions[5]; //get an array element value

int[][] products = { {100, 101, 102},

{200, 201, 202} }; //declare, create & initialize an array

a = products[0][0]; // a will equal 100. get a multidimensional array element value

b = products[0][1]; // b will equal 101

c = products[1][0]; // c will equal 200

d = products[1][2]; // d will equal 202

//the value 201 will be changed to 300. set a multidimensional array element vlaue

products[1][1] = 300;

m = products.length; // m will equal 2. get the number of array, the first dimension

n = products[1].length; // n will equal 3. get the number of elements in the array indexed by 1, the second dimension

[Exercise: Java Array Exercises]

Classes & Objects

A class defines an object by coding the properties and methods that appropriately manipulate the object. A class is the smallest structural element in Java. Java can only run code that is in a class. A class also defines a new data type. This data type has values and operations that can be done on those values. Objects are a specific instance of a class; objects are a specific instance of the new data type. One class has many instances, each unique, called objects. An object contains methods and methods contain Java statements. A program is constructed using objects to accomplish things and to interact with one another. A program can have many objects from the same class and/or objects from other classes. Because it is good practice to create classes and objects that do a specific set of tasks and only that, many objects are needed to construct a complete program. This section will cover some of the basic syntax associated with objects. More details are covered in the [Advanced Java Structural OO Syntax] section. The syntax below is the most basic. The items in bold are placeholders for actual code of the indicated type. The [ ] characters indicated that the contained item is optional. The ellipse (…) indicates that the previous item can be repeated multiple times. Many details such as access modifiers are not included in this section but are in the advanced section.

Defining a Class

The syntax that defines a class is:

class ClassName

{

//a class contains properties, methods and a special method called a constructor.

}

Defining Properties

Properties or fields are member elements of a class that contains a value. Properties can be read and written like variables. There is no code logic associated with properties. Properties are defined just like variable declarations.

DataType PropertyName [= value];

Defining Methods

Methods are member elements of a class that contains code logic. Methods can be invoked to perform an operation on a particular object (an instance of a class).

ReturnType MethodName([DataType Parameter, …])

{

//method logic using Java statements

//if ReturnType not void then a return statement with the correct type must be present

}

The ReturnType can be any of the primitive data types, an array or an object. If no type is to be returned then ReturnType is coded as void.

Defining Constructors

A constructor is a special method that is named the same as the class and is called when an object is created. It can be used to place the specific instance of the object in an initial state, in other words certain variable and properties can be given initial values and code logic can be performed. A constructor differs from a method in that it does not return anything; it is not even allowed to specify a return type, not even void, on a constructor’s definition. An object can have multiple constructors. Each will have the same name - the name of the class, but different parameters. This can be useful to allow users of the object different ways to create the object based on the parameters passed to the constructor. Remember the constructor name is the same as the class name.

ConstructorName([DataType Parameter, …])

{

//constructor logic using Java statements

}

Creating an Object

An object is created using the new operator. The new operator typically has a variable of the object type being created of the left side of the assignment operator (=), then the new operator keyword, then the constructor of the object to be invoked.

ClassName variable = new ConstructorName([parameters, …]);

This syntax can also be broken into two components and used to declare and create objects. This is often very useful.

ClassName variable;

variable = new ConstructorName([parameters, …]);

Object Literals

Java defines special syntax for creating instances of a very important and common class, the String class. A variable of type String is "automatically" created by simply assigning a string literal (set of characters within double quotes, eg. "hello there") to it.

String varName = "David";

Also, an object variable can be assigned the value null to indicate that the variable does not have an object reference. This can be used to "destroy" an object instance if the variable previously in the program had a valid object reference and then that variable is assigned to null. This causes the instance to be de-referenced and made available for garbage collection if no other references are held to the object.

Using an Object

An object contains members (fields and methods). To access these methods, an object variable has been declared and an instance of the object created first, then the members of that object instance are available through the objects variable name. The syntax to access the member is to specify the object instances variable name followed by a dot (.) and then the member name. If the member is a method then the name is followed by parentheses with any arguments that are necessary according to the method definition.

objectInstanceVariable.member; //for object fields

objectInstanceVariable.member(any args); //for object methods.

//multiple args are separated by commas.

Examples:

myVar = myObject.datafield1; //access an objects field, a value.

myVar2 = myObject.method1(a, 32, a/12+3); //access method that requires 3 arguments

Object-oriented vs. Function-oriented

At the heart of the OO paradigm is the use of an object. Consider the following lines of code.

a = area(c);

a = c.area();

In the first line the focus is on the function area in which a parameter is passed of type circle.

In the second line the focus is on the object c, this is why it is called object-oriented programming. The point is that we don’t have to pass an argument to the area "function", that is implicit in the syntax of object.method. This helps to ensure that bad parameters are not passed to the area function.

Copying and Comparing Objects

Copying and comparing objects is like copying and comparing arrays. You can copy or compare object references or the "value" of the object. To copy an object reference you simply assign an object variable to another of the same or compatible type. To copy the contents of one object to another use the clone() method. To compare an object reference with another object reference use the == operator. To compare the contents of one object with another use the equals() method. Depending on the objects definition the clone() and equals() methods may or may not exists, and how they are compared or cloned is determined. It may be that the compare or clone actually does the simple object reference compare or clone, or it may be much more sophisticated. The same issue of shallow and deep copies and compares is present with objects as with arrays.

Object Self-Reference

An object instance can refer to itself in the code that defines the class that the object is created from by using the keyword "this". The keyword "this" is special syntax that acts like an object reference variable. It is automatically assigned to the value of the instance of the object that is currently being used. It is used within the code of the object and refers to that particular object’s unique instance. If you execute code in another object instance of the same class then the value of "this" in that code is the reference to this other object instance. In other words, the "this" keyword is replaced at runtime with the reference to the particular object’s instance that is being executed at the moment. We will see later where this special syntax is useful.

[Exercise: Java Classes and Objects]

Java Platform Specifics

String Object

Strings are foremost an object in Java, however there are some special characteristics that integrates strings into the syntax of Java statements. String objects can be created without the new operator. Most typically assigning an expression to a string variable creates a string. In fact every time a value is assigned to a string variable, an object is created, even if the variable had a previous value. In that case the old object is de-reference and flagged for garbage collection and a new string object is created with the new value. Thus, strings do have the overhead of objects but the integrated syntax allows strings to be used much like primitive data types. The notable exceptions are that the comparative operators used on string variables refer to the reference value of the string, not the actual value. In these cases the strings are treated like objects and methods must be called for such operations as testing for equality to another string. The plus (+) operator however is allowed and it will combine actual string values into a new string value. Keep in mind when coding a program that there is no continuation syntax for a string that is more than one line long. In those cases the + operator should be used to build the entire string’s value. The java.lang.String object has many methods that are useful for manipulating strings. In "Java in a Nutshell", 3rd Edition, refer to pages 138-140 and 365-366. In "Just Java 2", 4th Edition, refer to pages 98-101.

Examples:

String s = "Hello There"; //notice String is capitalize, an object.
s = s+"!";

int a = 13;
s = s+" "+a; //s will = "Hello There! 13".
//The int a is automatically converted to the text representation of //the integer value.

//this is how to test for equality
boolean testString = s.equals("Hello There! 13");

//a long string coded with concatenation (+)
String z = "This is a string that requires more than one line to "
	+ "contain it's entire value.";
//notice z is constructed from 2 literal string concatenated together.

Wrapper classes for primitive data types

Each of the primitive data types has a corresponding object. These objects are known as "wrapper" objects or classes. These objects provide useful methods and constants. Most notably are the methods to convert a string to a primitive data type if possible. In "Java in a Nutshell", 3rd Edition, refer to pages 140-141 and 365-366. In "Just Java 2", 4th Edition, refer to pages 195-196. Another useful trait of these wrapper objects is that they are objects. Many useful methods in other objects require parameters to be of type object. When you have a primitive data type variable that you want to pass to one of these methods, you make a wrapper object to have the same value as the primitive data type and pass the wrapper object instance. Once you return from the method you can update the primitive data type variable with the value in the wrapper object if appropriate.

Examples:

// changes int to Integer and back
Integer myIntObj;
int i = 42;
myIntObj = new Integer(i);
i = myIntObj.intValue();

String s = "123";
int a = Integer.parseInt(s); //a=123

Table of primitive data types and their wrapper classes.

Primitive Type

Corresponding "Wrapper" Class

boolean

Boolean

char

Character

byte

Byte

short

Short

int

Integer

long

Long

float

Float

double

Double

[Programming Assignment 5: Strings and Wrappers]

Exception Handling

Java provides a facility to handle exception conditions that are separate from the general logic of the program and in particular, it is separate from the return value of a method call. In other languages exception conditions are indicated with special values returning from a function call. If the return value was not a special value then the method executed properly. There is usually no standard for these special values. It is poor programming practice because one variable is being used for multiple purposes (one for a valid return value, the other to indicate an exception condition). This led to error processing logic being intermingled, line for line with application logic. With Java’s separate exception-handling facility there are no special values to indicate an error returned from methods, and exception-handling logic is not a closely intermingled with the application logic.

Throw, throws, try/catch/finally

Java has three components to its exception handling facility. The first component is the declaration in the method signature that the method can and may cause a particular exception to occur. By specifying this, others who use the method can know what exceptions that they have to deal with in some fashion. Also, the Java compiler and runtime system know that you must have dealt with the exception in your code somehow. The exceptions that are supplied in the method signature are actually objects that are sub-classed from the Exception object provided by Java. The second component is the ability to actually raise an exception due to a condition that indicates the specified type of exception. In the code of a method, as the code detects an exception condition it can issue (raise, throw) the exception. In other words, the exception object that indicates the type of exception is thrown by the method to the caller of the method. The caller of the method must deal with the possibility that an exception could be thrown to it. This is done by the third component. Since the code statement that calls a method is also in another method, this calling method could simply specify in its method signature that it throws that particular exception. This does nothing more than cause the caller of this method that have to deal with the exception. It could deal with it by continuing to declare that it throws the exception back up the call chain. If this is continually done then eventually the exception will be thrown back to the Java runtime environment, which will terminate the program with an error message. If one the other hand you want to take care of the exception and not pass it off to someone else, you can "catch" the thrown exception. To do this however, you first code that you are going to try a set of statements and if any of those cause the particular exception, then you catch that exception and handle it with code associated with the catch block. A method that is called may throw many different exceptions or the code in a try block may do different things that may cause different exceptions. With each try block you can have multiple catch blocks, each to catch a particular exception. In addition to or in place of the catch block(s) you can have a finally block. Regardless of what happens in the try block the finally block is guaranteed to be executed. The only time the finally block is not executed is if the program is terminated in the try or a catch block that is executed due to an exception. Program termination occurs due to an unrecoverable error or calling the System.exit() method. Further details can be found in Java in a Nutshell, 3rd Edition, pg. 55-59.

Throws, Throw, Try/Catch/Finally and Creating your own Exception object Example:

public class FileEmptyException extends Exception
{
	public FileEmptyException()
	{
		FileEmptyException("FILE EMPTY");
	}

	public FileEmptyException(String message)
	{
		super(message);
	}

} //end class FileEmptyException


public class test
{

public static File fileExists(String filename) throws FileNotFoundException, IOException, FileEmptyException
{
	File f1 = open(filename);
	if (f1.length() == 0)
	{
		throw new FileEmptyException("The file is empty.");
	}
	return (f1);
} //end fileExists

public static void main(String args[])
{
	File f1;

	try
	{
		f1 = fileExists("myfile.txt");
	}
	catch (FileEmptyException e)
	{
	}
	catch (FileNotFoundException e)
	{
	}
	catch (IOException e)
	{
	}
	catch (Exception e)
	{
	}
	finally
	{
		closeFile(f1);
	}
} //end main

} //end class test

 

Exception Object Hierarchy Implications

Exceptions can form an inheritance hierarchy. This hierarchy forms an ordering for those exceptions. This ordering has implication for the order of the catch blocks that catch those possible exceptions. The order of the catch blocks for exceptions in a hierarchy is from the last child object back up through the successive parents of the hierarchy. In the example above the FileNotFoundException is a child of the IOException object, which is turn is a child of the Exception object. This means that the catch block for the FileNotFoundException must be before the IOException catch block. The IOException must be before the Exception catch block. Since the FileEmptyException is only a child of the Exception object its order must be before the Exception catch block but is independent of the order of the FileNotFoundException and IOException catch blocks. It could have been place anywhere after the try block and before the Exception catch block.

Parent exception classes: Throwable, Exception, and Error

The general term exception (an abnormal condition) has two specific meanings in the Java language. First, an exception can be an Error. An error is an unrecoverable abnormal condition and usually results in program termination. Examples of Errors are ClassFormatError, OutofMemoryError. Errors can occur at any point in the execution of a program. Secondly, an exception can be an Exception. An Exception is a condition that is not as catastrophic as an error and recoverable actions may be able to take place. Exceptions are subdivided into two types, checked and unchecked. These are covered in the next section. Examples of Exceptions, one of each type, are IOException and IllegalArgumentException. Both the Error and Exception classes are subclasses (children) of the Throwable class. The Throwable class contains the common factors of the Error and Exception classes.

Checked vs. Unchecked Exceptions

The distinction between Checked and Unchecked Exceptions is that Checked Exceptions arise in specific, well-defined circumstance, for example when you try to open a file, a FileNotFoundException may occur. However, it will not occur in arbitrary circumstances. On the other hand, Unchecked Exceptions may occur at essentially anytime in a program. Errors are considered unchecked exceptions and are generally unrecoverable conditions. Unchecked Exceptions that are not of type Error are possibly recoverable. The importance of the distinction is that when you use a method that "throws" checked exceptions then you must either catch the exceptions or declare in you method signature that your method throws that exception. For unchecked exception, if they are Errors then there is not much that can be done, if they are Exceptions then you can catch them or declare that your method throws them but you are not required to.

When and How to deal with Exceptions

For all checked Exceptions and the unchecked Exceptions that you choose to deal with, you have two choices about how to deal with them. First, you can choose to do nothing more than continue to throw the exceptions up to the parent object method of the object that encounters the exception. The second choice is to deal with the exception at the point in which it occurs or is no longer to be thrown up to a parent object to deal with it. Placing the "throws exception" clause in the method signature of where that exception may occur does the first method. This will direct the Java environment to signal the parent method that the exception occurred. This method has the same two choices. As indicated in the Throw, throws, try/catch/finally section the exception may propagate all the way up until Java is forced to terminate the program because the exception was not dealt with. Using the catch block deals with the exception at the place in which it occurs or is no longer thrown up to a parent object, this is the second method of dealing with exceptions.

The general rule for which choice to take is, at the place where you can write code to recover from the exception is where you should catch the exception. If you can’t recover from the exception but a parent class can, then throw the exception up the class hierarchy. If you can’t recover and no parent will recover from the exception either, then your recovery should consist of printing a meaningful message and possibly terminating the program gracefully. It is better to do this than to just let Java terminate the program with some kind of default message that may not clearly state the reasons for the termination.

Code Organization with try/catch in Mind

Exception handling with try/catch blocks will have an impact on code organization, particularly when the try/catch blocks are in a loop structure. The choice of exception handling code organization should be determined by the appropriate loop structure, a while loop (execute zero or more times), or do while loop (execute one or more times). Do not choose the loop structure based on the exception handling code organization. Below are two examples of different techniques of exception handling code organization and looping structures.

Example 1: Always ask for input at least once.
public static void main(String args[])
{
	BufferedReader console;
	console = new BufferedReader(new InputStreamReader(System.in));
	String intstring = "";

	do
	{
		try
		{
			System.out.print("Enter an integer number: ");
			intstring = console.readLine();
		}
		catch (IOException e)
		{
		}

		if (intstring.equals("")) 
			break;
		// process input
	} while (true);
}


Example 2: Organize code such that the file can exist but be empty of data.
//code fragments
static BufferedReader fileIn;
   
static String readDatum()
{
	String datumRead = "";
      
	try
	{
		datumRead = fileIn.readLine();
	}
	catch (IOException e)
	{
	}
	return datumRead;
}

//code fragment
	try
	{
		fileIn = new BufferedReader(new FileReader("data.txt"));
	}
	catch (FileNotFoundException e)
	{
		System.out.println("ERROR: "+e.getMessage());
		System.exit(1);
	}
      
	while ( (dataIn=readDatum()) != null )
	{
		// process data
	}
//end fragment

[Exercise: Java Exception Handling]

[Programming Assignment 6: Student Courses]